package com.coovane.bytetrix.common.validation;

import com.coovane.bytetrix.common.annotation.ValidPassword;
import com.coovane.bytetrix.common.enumeration.ErrorCodeEnum;
import com.coovane.bytetrix.common.exception.GenericAssert;
import com.coovane.bytetrix.common.exception.GenericException;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.passay.*;

import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 密码验证器，使用了Passay开源框架
 * </p>
 *
 * @author: Hsu
 * @date: 2022/12/8 22:21
 * @copyright: companyName
 * @see
 * @since 1.8
 */
public class PasswordConstraintValidator implements ConstraintValidator<ValidPassword, String> {

    @Override
    public void initialize(ValidPassword constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        PasswordValidator passwordValidator = new PasswordValidator(Arrays.asList(
                // 密码长度是8~18位
                new LengthRule(8,18),
                // 必须有一个大写字母
                new CharacterRule(EnglishCharacterData.UpperCase,1),
                // 必须有一个小写字母
                new CharacterRule(EnglishCharacterData.LowerCase,1),
                // 必须有一个特殊字符
                new CharacterRule(EnglishCharacterData.Special,1),
                // 不允许出现连续的5个字母
                new IllegalSequenceRule(EnglishSequenceData.Alphabetical,5,false),
                // 不允许出现连续的5个数字
                new IllegalSequenceRule(EnglishSequenceData.Numerical, 5, false),
                // 不允许出现美式键盘连续的字符，如qwert，asdf
                new IllegalSequenceRule(EnglishSequenceData.USQwerty,5,false),
                // 不允许有空格，回车等字符
                new WhitespaceRule()
        ));
        RuleResult ruleResult = passwordValidator.validate(new PasswordData(value));
        // 解析规则校验结果
        return ruleResultMessageResolver(ruleResult);
    }

    /**
     * 解析规则校验结果
     *
     * @param ruleResult
     */
    private boolean ruleResultMessageResolver(RuleResult ruleResult) {
        if (!ruleResult.isValid()) {
            List<RuleResultDetail> ruleResultDetails = ruleResult.getDetails();
            ruleResultDetails.stream().forEach(resultDetail -> {
                String errorCode = resultDetail.getErrorCode();
                ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.resolveLocale(errorCode.toLowerCase());
                String formatMessage = String.format(errorCodeEnum.getErrorMsg(), resultDetail.getValues());
                GenericAssert.isTrue(ruleResult.isValid(), new GenericException(errorCodeEnum, formatMessage));
            });
            return false;
        }
        return true;
    }

}
